use std::{
    any::Any,
    ops::{Deref, DerefMut},
    sync::mpsc::Sender,
};

use egui::{Align2, Frame, Rect, Ui, Vec2};
use serde::{Deserialize, Serialize};
use thunderdome::{Arena, Index};
use QcCore::ecs::component::{BaseComponentTrait, Named};
use QcTools::message::messageSender::MessageSender;

use crate::{
    component::{Button, Grid, Image, Label, Panel, TextBox, Widget},
    core::context::UiContext,
    message::UiMessage,
};

use super::Canvas;

#[typetag::serde(tag = "type")]
pub trait UiNodeTrait: BaseComponentTrait + SetId + WidgetExt {
    fn render(&mut self, ctx: &mut UiContext) {
        let frame = self.renderFrame(ctx);
        let UiContext {
            ui,
            sender,
            canvas_ptr,
        } = ctx;

        frame.show(ctx.ui, |ui| {
            self.renderInner(&mut UiContext::new(ui, sender).with_canvas_ptr(*canvas_ptr))
        });
    }

    fn renderTop(&mut self, ctx: &mut UiContext) {
        let frame = self.renderFrame(ctx);
        let UiContext {
            ui,
            sender,
            canvas_ptr,
        } = ctx;

        egui::CentralPanel::default()
            .frame(frame)
            .show(ui.ctx(), move |ui| {
                self.renderInner(&mut UiContext::new(ui, sender).with_canvas_ptr(*canvas_ptr))
            });
    }

    fn renderArea(&mut self, ctx: &mut UiContext) {
        let frame = self.renderFrame(ctx);
        let UiContext {
            ui,
            sender,
            canvas_ptr,
        } = ctx;

        let widget = self.get_widget();
        let area = egui::Area::new(format!("ID{:?}-{}", widget.id, widget.name))
            .fixed_pos(self.get_widget().world_position);

        area.show(ctx.ui.ctx(), |ui| {
            frame.show(ui, |ui| {
                self.renderInner(&mut UiContext::new(ui, sender).with_canvas_ptr(*canvas_ptr))
            });
        });
    }

    fn renderFrame(&self, ctx: &mut UiContext) -> egui::Frame {
        Frame::none()
    }

    fn renderInner(&mut self, ctx: &mut UiContext) {}

    fn get_rect(&self) -> Rect {
        self.get_widget().get_rect()
    }
}

pub trait WidgetExt {
    fn get_widget(&self) -> &Widget;

    fn get_widget_mut(&mut self) -> &mut Widget;
}

pub trait ToUi: Sized + UiNodeTrait {
    fn toUi(self) -> UiNode;
}

pub trait SetId {
    fn setId(&mut self, id: Index);
}

impl Deref for UiNode {
    type Target = dyn UiNodeTrait;

    fn deref(&self) -> &Self::Target {
        self.get_value()
    }
}

impl DerefMut for UiNode {
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.get_value_mut()
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub enum UiNode {
    Button(Button),
    Grid(Grid),
    Panel(Panel),
    Label(Label),
    TextBox(TextBox),
    Image(Image),
    Other(Box<dyn UiNodeTrait>),
}

impl UiNode {
    pub fn get_value(&self) -> &dyn UiNodeTrait {
        match self {
            UiNode::Button(node) => node,
            UiNode::Grid(node) => node,
            UiNode::Panel(node) => node,
            UiNode::Label(node) => node,
            UiNode::TextBox(node) => node,
            UiNode::Image(node) => node,
            UiNode::Other(node) => node.as_ref(),
        }
    }

    pub fn get_value_mut(&mut self) -> &mut dyn UiNodeTrait {
        match self {
            UiNode::Button(node) => node,
            UiNode::Grid(node) => node,
            UiNode::Panel(node) => node,
            UiNode::Label(node) => node,
            UiNode::TextBox(node) => node,
            UiNode::Image(node) => node,
            UiNode::Other(node) => node.as_mut(),
        }
    }
}
